//
//  MazeGameVC+PlayGame.swift
//  MazeGame
//
//  Created by orienthong on 2018/12/21.
//  Copyright © 2018 OrientHong. All rights reserved.
//

import SceneKit
import UIKit

extension MazeGameVC {
    
    func panCamera(_ displacement: float2, firstPan: inout Bool) {
        //如果在进行游戏
        if self.isGamming {
            if self.panningType == .camera {
                var directionToPan = displacement
                directionToPan *= float2(1.0, -1.0)
                let F = SCNFloat(0.005)
                if firstPan {
                    cameraXHandle.rotation = SCNVector4(x: 1.0, y: 0.0, z: 0.0, w: 2 * .pi)
                    cameraYHandle.rotation = SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 0)
                    firstPan = false
                    return
                }
                SCNTransaction.animateWithDuration(0.0) {
                    if self.cameraYHandle.rotation.y < 0 {
                        self.cameraYHandle.rotation = SCNVector4(0, 1, 0, -self.cameraYHandle.rotation.w)
                    }
                    
                    if self.cameraXHandle.rotation.x < 0 {
                        self.cameraXHandle.rotation = SCNVector4(1, 0, 0, -self.cameraXHandle.rotation.w)
                    }
                }
                // Update the camera position with some inertia.
                SCNTransaction.animateWithDuration(0.5, timingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)) {
                    self.cameraYHandle.rotation = SCNVector4(0, 1, 0, self.cameraYHandle.rotation.y * (self.cameraYHandle.rotation.w - SCNFloat(directionToPan.x) * F))
                    self.cameraXHandle.rotation = SCNVector4(1, 0, 0, min(max(self.cameraXHandle.rotation.w + SCNFloat(directionToPan.y) * F, 5.5), 7.0))
                }
                guard let direction = self.gameScene.getDirection(with: cameraYHandle.eulerAngles) else {
                    self.cameraDircetion = .forward
                    return
                }
                self.cameraDircetion = direction
            } else {
                //持续获取手指滑动方向
                getFingerMoveDirection(wint: displacement)
                
                SCNTransaction.animateWithDuration(0.5, timingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)) {
                    moveSphere(displacement)
                }
            }
        }
        //俯瞰状态
        else {
            
        }
    }
    
    
    func playGameTouchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard self.isGamming else { return }
        let location = touches.first!.location(in: self.sceneView)
        if location.y < divider {
            panningType = .camera
        } else {
            panningType = .sphere
        }
        if panningTouch == nil {
            panningTouch = touches.first
        }
    }
    
    func playGameTouchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard self.isGamming else { return }
        if let touch = panningTouch {
            let previousLocationt = float2(touch.previousLocation(in: sceneView))
            let currentLocation = float2(touch.location(in: sceneView))
            let displacement = currentLocation - previousLocationt
            self.panCamera(displacement, firstPan: &firstPan)
        }
    }
    
    func playGameTouchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard self.isGamming else { return }
        panningTouch = nil
        SCNTransaction.animateWithDuration(0.5, timingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut), completionBlock: nil) {
            self.cameraYHandle.position.x = self.cameraYHandle.position.x.rounded()
            self.cameraYHandle.position.z = self.cameraYHandle.position.z.rounded()
            self.sphereNode.position.x = self.cameraYHandle.position.x
            self.sphereNode.position.z = self.cameraYHandle.position.z
        }
    }
    
    func playGameTouchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard self.isGamming else { return }
        panningTouch = nil
        SCNTransaction.animateWithDuration(0.5, timingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut), completionBlock: nil) {
            self.cameraYHandle.position.x = self.cameraYHandle.position.x.rounded()
            self.cameraYHandle.position.z = self.cameraYHandle.position.z.rounded()
            self.sphereNode.position.x = self.cameraYHandle.position.x
            self.sphereNode.position.z = self.cameraYHandle.position.z
        }
    }
    
    //Start Game
    func startGame() {
        self.sceneView.removeGestureRecognizer(swipeUp)
        self.sceneView.removeGestureRecognizer(swipeDown)
        
        //1.重设camera的根节点
        resetCameraNode()
        
        //2.添加倒计时节点
        addBadge()
        
        //3.开始倒计时
        startTimer()
        
        
        
    }
    //1.重设camera的根节点
    func resetCameraNode() {
        let pov = self.sceneView.pointOfView!
        pov.removeFromParentNode()
        //pov.camera.zFar = 100
        //pov.camera.zNear = 0.3
        pov.position = SCNVector3Zero
        pov.eulerAngles = SCNVector3Zero
        cameraXHandle.removeFromParentNode()
        cameraYHandle.removeFromParentNode()
        
        self.gameScene.rootNode.addChildNode(cameraYHandle)
        cameraYHandle.position = SCNVector3Make(0, self.configurator.cameraHeight, 0)
        cameraYHandle.eulerAngles = SCNVector3Make(-.pi/2, 0, 0)
        cameraYHandle.addChildNode(cameraXHandle)
        cameraYHandle.name = "camera"
        cameraXHandle.position = SCNVector3Zero
        cameraXHandle.eulerAngles = SCNVector3Zero
        cameraXHandle.name = "camera"
        cameraXHandle.addChildNode(pov)
        pov.position = SCNVector3Zero
        pov.eulerAngles = SCNVector3Zero
    }
    
    func startTimer() {
        self.countdownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
        
    }
    @objc func updateTime() {
        //游戏进行中
        if self.isGamming {
            if self.gammingTotalTime != 0 {
                self.gammingTotalTime -= 1
            } else {
                endTimer()
            }
        }
        //记忆迷宫
        else {
            if self.rememberTotalTime != 0 {
                SCNTransaction.animateWithDuration(0.0) {
                    let material = self.countNode.geometry?.firstMaterial
                    self.countNode.geometry = nil
                    let nodeString = NSAttributedString(string: "\(self.rememberTotalTime)",
                                                    attributes: [NSAttributedString.Key.font: UIFont(name: "Helvetica", size: 42.0)!])
                    let text = SCNText(string: nodeString, extrusionDepth: 5)
                    text.chamferRadius = 2.5
                    self.countNode.geometry = text
                    self.countNode.geometry?.firstMaterial = material
                }
                self.rememberTotalTime -= 1
            } else {
                endTimer()
            }
        }
    }
    func endTimer() {
        if self.isGamming {
            
        } else {
            //进入游戏场景
            SCNTransaction.animateWithDuration(0.5, completionBlock: {
                self.isGamming = true
                //remove countDown node
                self.gameScene.rootNode.childNode(withName: "newBadgeNode", recursively: true)!.removeFromParentNode()
            }, animations: {
                //self.gameSphere.opacity = 0.0
                self.cameraYHandle.position = SCNVector3Make(Float(self.configurator.Entrance.x - self.configurator.Matrix.count/2), 1.2, Float(self.configurator.Entrance.z - self.configurator.Matrix.count/2))
                self.cameraYHandle.eulerAngles = SCNVector3Zero
                
            })
        }
    }
    
    func addBadge() {
        let newBadgeNode = SCNNode()
        newBadgeNode.name = "newBadgeNode"
        let badgeScene = SCNScene(named: "art.scnassets/scn/newBadge.scn")!
        let badgeNode = badgeScene.rootNode.childNode(withName: "newBadge", recursively: true)!
        newBadgeNode.addChildNode(badgeNode)
        newBadgeNode.position = SCNVector3Make(10, 20, -10);
        newBadgeNode.eulerAngles = SCNVector3Make(Float(-90).degreesToRadians, 0, 0)
        newBadgeNode.scale = SCNVector3Make(0.03, 0.03, 0.03)
        newBadgeNode.opacity = 0.0
        self.countNode = badgeNode.childNode(withName: "badgeImage", recursively: true)!
        self.countNode.geometry?.firstMaterial?.emission.intensity = 0.0
        
        let newBadgeAnimation = badgeNode.animation(forKey: badgeNode.animationKeys[0])!
        badgeNode.removeAllAnimations()
        
        newBadgeAnimation.speed = 1.5
        newBadgeAnimation.fillMode = .both
        newBadgeAnimation.usesSceneTimeBase = false
        newBadgeAnimation.isRemovedOnCompletion = false
        newBadgeAnimation.repeatCount = 0
        
        newBadgeNode.opacity = 1.0
        let ropeNode = newBadgeNode.childNode(withName: "rope02", recursively: true)!
        ropeNode.opacity = 1.0
        
        self.gameScene.rootNode.addChildNode(newBadgeNode)
        newBadgeNode.addAnimation(newBadgeAnimation, forKey: "animation")
        
        SCNTransaction.begin()
        SCNTransaction.animationDuration = 2.0
        newBadgeNode.position = SCNVector3Make(5, 12, -6.5)
        newBadgeNode.opacity = 1.0
        countNode.geometry?.firstMaterial?.emission.intensity = 0.4
        
        SCNTransaction.commit()
    }
    
    
    //Utils
    /// 获取手指滑动方向
    func getFingerMoveDirection(wint displacement: float2) {
        let absValue = abs(displacement)
        if absValue.x > absValue.y {
            if absValue.x >= 1 {
                if displacement.x > 0 {
                    currentFingerDirection = .right
                    if previousFingerDirection == .forward || previousFingerDirection == .backward {
                        if absValue.y >= 1 {
                            previousFingerDirection = currentFingerDirection
                        } else {
                            currentFingerDirection = previousFingerDirection
                        }
                    }
                }
                else {
                    currentFingerDirection = .left
                    if previousFingerDirection == .forward || previousFingerDirection == .backward {
                        if absValue.y >= 1 {
                            previousFingerDirection = currentFingerDirection
                        } else {
                            currentFingerDirection = previousFingerDirection
                        }
                    }
                }
            }
        }
        else {
            if absValue.y >= 1 {
                if displacement.y > 0 {
                    currentFingerDirection = .backward
                    if previousFingerDirection == .left || previousFingerDirection == .right {
                        if absValue.y >= 2 {
                            previousFingerDirection = currentFingerDirection
                        } else {
                            currentFingerDirection = previousFingerDirection
                        }
                    }
                    //print("⬆️")
                }
                else {
                    currentFingerDirection = .forward
                    if previousFingerDirection == .left || previousFingerDirection == .right {
                        if absValue.y >= 2 {
                            previousFingerDirection = currentFingerDirection
                        } else {
                            currentFingerDirection = previousFingerDirection
                        }
                    }
                    //print("⬇️")
                }
            }
        }
    }
    
    private func checkHorizontal() -> Bool {
        for range in self.configurator.XcloseRanges[self.currentLocation.z] {
            if range.contains(7+self.cameraYHandle.position.x) {
                return true
            }
        }
        return false
    }
    
    private func checkVetical() -> Bool {
        for range in self.configurator.ZcloseRanges[self.currentLocation.x] {
            if range.contains(7+self.cameraYHandle.position.z) {
                return true
            }
        }
        return false
    }
    func moveSphere(_ displacement: float2) {
        switch self.cameraDircetion {
        case .forward:
            switch self.currentFingerDirection {
            case .forward, .backward:
                self.cameraYHandle.position.z += displacement.y * 0.05
                if checkVetical() {
                    self.currentLocation.z = Int(self.cameraYHandle.position.z.rounded()+7)
                }
                else {
                    self.cameraYHandle.position.z = Float(self.currentLocation.z-7)
                }
            case .left, .right:
                self.cameraYHandle.position.x += displacement.x * 0.05
                if checkHorizontal() {
                    self.currentLocation.x = Int(self.cameraYHandle.position.x.rounded()+7)
                } else {
                    self.cameraYHandle.position.x = Float(self.currentLocation.x-7)
                }
            }
        case .backward:
            switch self.currentFingerDirection {
            case .forward, .backward:
                self.cameraYHandle.position.z -= displacement.y * 0.05
                if checkVetical() {
                    self.currentLocation.z = Int(self.cameraYHandle.position.z.rounded()+7)
                }
                else {
                    self.cameraYHandle.position.z = Float(self.currentLocation.z-7)
                }
            case .left, .right:
                self.cameraYHandle.position.x -= displacement.x * 0.025
                if checkHorizontal() {
                    self.currentLocation.x = Int(self.cameraYHandle.position.x.rounded()+7)
                } else {
                    self.cameraYHandle.position.x = Float(self.currentLocation.x-7)
                }
            }
        case .left:
            switch self.currentFingerDirection {
            case .forward, .backward:
                self.cameraYHandle.position.x += displacement.y * 0.05
                if checkHorizontal() {
                    self.currentLocation.x = Int(self.cameraYHandle.position.x.rounded()+7)
                } else {
                    self.cameraYHandle.position.x = Float(self.currentLocation.x-7)
                }
            case .left, .right:
                self.cameraYHandle.position.z -= displacement.x * 0.025
                if checkVetical() {
                    self.currentLocation.z = Int(self.cameraYHandle.position.z.rounded()+7)
                }
                else {
                    self.cameraYHandle.position.z = Float(self.currentLocation.z-7)
                }
            }
        case .right:
            switch self.currentFingerDirection {
            case .forward, .backward:
                self.cameraYHandle.position.x -= displacement.y * 0.05
                if checkHorizontal() {
                    self.currentLocation.x = Int(self.cameraYHandle.position.x.rounded()+7)
                } else {
                    self.cameraYHandle.position.x = Float(self.currentLocation.x-7)
                }
            case .left, .right:
                self.cameraYHandle.position.z += displacement.x * 0.025
                if checkVetical() {
                    self.currentLocation.z = Int(self.cameraYHandle.position.z.rounded()+7)
                }
                else {
                    self.cameraYHandle.position.z = Float(self.currentLocation.z-7)
                }
            }
        }
        self.sphereNode.position.x = self.cameraYHandle.position.x
        self.sphereNode.position.z = self.cameraYHandle.position.z
    }
}
